local config = require("config")
local str_util = require("lib.string_util")

local _M = {}

-- 排除域名各个作用范围常量
_M.XHOST_SCOPE_ALL = "all"
_M.XHOST_SCOPE_IP_WHITE = "ip_white"
_M.XHOST_SCOPE_IP_BLACK = "ip_black"
_M.XHOST_SCOPE_IP_FOREIGN = "ip_foreign"
_M.XHOST_SCOPE_UA = "ua"
_M.XHOST_SCOPE_COOKIE = "cookie"
_M.XHOST_SCOPE_CC = "cc"
_M.XHOST_SCOPE_ARGS = "args"
_M.XHOST_SCOPE_POST = "post"
_M.XHOST_SCOPE_HEADER = "header"

-- 排除域名缓存前缀
local exhost_cache_name_prefix = {}
exhost_cache_name_prefix[_M.XHOST_SCOPE_ALL] = "xh:all:"
exhost_cache_name_prefix[_M.XHOST_SCOPE_IP_WHITE] = "xh:ipw:"
exhost_cache_name_prefix[_M.XHOST_SCOPE_IP_BLACK] = "xh:ipb:"
exhost_cache_name_prefix[_M.XHOST_SCOPE_IP_FOREIGN] = "xh:ipf:"
exhost_cache_name_prefix[_M.XHOST_SCOPE_UA] = "xh:ua:"
exhost_cache_name_prefix[_M.XHOST_SCOPE_COOKIE] = "xh:cook:"
exhost_cache_name_prefix[_M.XHOST_SCOPE_CC] = "xh:cc:"
exhost_cache_name_prefix[_M.XHOST_SCOPE_ARGS] = "xh:get:"
exhost_cache_name_prefix[_M.XHOST_SCOPE_POST] = "xh:post:"
exhost_cache_name_prefix[_M.XHOST_SCOPE_HEADER] = "xh:hdr:"

---解析排除域名(主要是解析通配符域名)
---     返回 {
---         wildcard = {"a.com","b.com"},  --通配符域名
---         normal = {"www.x.com"}         --具体域名
---     }
---@param ex_list table 待解析的排除域名列表
---@return table
local function parse_ex_host(ex_list)
    local result = {
        wildcard = {},
        normal = {}
    }
    for _, host in ipairs(ex_list) do
        -- 以 *. 开头的 通配符域名
        local from, to = string.find(host, "^%*%.")
        if to then
            local res = string.sub(host, to + 1)
            if string.len(res) > 1 then
                table.insert(result.wildcard, string.lower(res))
            end
        else
            -- 具体域名
            table.insert(result.normal, string.lower(host))
        end
    end

    return result
end

-- 检测域名是否为config中配置的排除域名
do
    local dict_cache = ngx.shared.easy_waf_cache
    ---检测域名是否为指定作用范围内的排除域名
    ---@param host string   待检测域名
    ---@param scope string | nil  作用范围(nil:等同于"all"全局)
    ---     可用参数值有:
    ---         "all" / nil 全局
    ---         "ip_white" IP白名单检测阶段
    ---         "ip_black" IP黑名单检测阶段
    ---         "ip_foreign" 境外IP检测阶段
    ---         "ua" USER-AGENT检测阶段
    ---         "cookie" COOKIE检测阶段
    ---         "cc" CC检测阶段
    ---         "args" GET参数检测阶段
    ---         "post" POST参数检测阶段
    ---         "header" HEADER检测阶段
    ---@return boolean
    local function _is_ex_host(host, scope)
        local cache_prefix
        local _scope
        if not scope then
            cache_prefix = exhost_cache_name_prefix["all"]
            _scope = "all"
        else
            _scope = string.lower(scope)
            if not exhost_cache_name_prefix[_scope] then
                -- 传入的 scope 参数不在可选值列表中，直接返回false
                return false
            else
                cache_prefix = exhost_cache_name_prefix[_scope]
            end
        end

        local _host = string.lower(host)
        local cache_key = cache_prefix .. _host
        local res = dict_cache:get(cache_key)
        if not res then
            -- 没缓存，解析对应scope配置中的排除列表
            local ex_host_tbl = parse_ex_host(config.host_x[_scope])
            for _, v in ipairs(ex_host_tbl["normal"]) do
                if _host == v then
                    -- 排除域名 设置缓存为1
                    dict_cache:set(cache_key, 1)
                    return true
                end
            end
            for _, v2 in ipairs(ex_host_tbl["wildcard"]) do
                if string.find(_host, "%.?" .. str_util.escpattern(v2) .. "$") then
                    -- 排除域名 设置缓存为1
                    dict_cache:set(cache_key, 1)
                    return true
                end
            end
            -- 非排除域名 设置缓存为0
            dict_cache:set(cache_key, 0)
        elseif res == 1 then
            return true
        end
        return false
    end
    _M.is_ex_host = _is_ex_host
end

return _M
